package com.gqh.weather.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gqh.weather.auth.UserContext;
import com.gqh.weather.config.FileConfig;
import com.gqh.weather.config.MinioConfig;
import com.gqh.weather.domain.dto.MyPage;
import com.gqh.weather.domain.dto.StudentImportDTO;
import com.gqh.weather.domain.dto.StudentListData;
import com.gqh.weather.domain.dto.StudentListRequest;
import com.gqh.weather.domain.dto.StudentUpdateRequest;
import com.gqh.weather.domain.entity.CcSchoolStudentCount;
import com.gqh.weather.domain.entity.School;
import com.gqh.weather.domain.entity.Student;
import com.gqh.weather.domain.entity.Task;
import com.gqh.weather.domain.enums.NianjiEnum;
import com.gqh.weather.exception.BusinessException;
import com.gqh.weather.exception.Result;
import com.gqh.weather.mapper.*;
import com.gqh.weather.util.MinioUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;

/**
 * 学生管理服务类
 */
@Slf4j
@Service
public class StudentService extends ServiceImpl<StudentMapper, Student> {

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private SchoolMapper schoolMapper;

//    @Autowired
//    private ExamAddressMapper examAddressMapper;
//
//    @Autowired
//    private ExamRoomMapper examRoomMapper;

    @Autowired
    private CcSchoolStudentCountMapper ccSchoolStudentCountMapper;
    
    @Autowired
    private CityMapper cityMapper;
    
    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private MinioClient minioClient;
    
    @Autowired
    private MinioConfig minioConfig;
    
    @Autowired
    private FileConfig fileConfig;

    /**
     * 学生列表查询
     *
     * @param request 查询请求
     * @return 查询结果
     */
    public Result<MyPage<StudentListData>> getStudentList(StudentListRequest request) {
        try {
            // 验证任务是否存在
            Task task = taskMapper.selectById(request.getTaskId());
            if (task == null) {
                throw new BusinessException("任务不存在");
            }
            
            // 创建分页对象
            Page<StudentListData> page = new Page<>(request.getPage(), request.getCount());
            
            // 获取关键字
            String keyword = StringUtils.hasText(request.getKeyword()) ? request.getKeyword() : null;
            
            // 获取城市代码列表
            List<String> codes = new ArrayList<>();
            codes.add(request.getCitycode());
            codes.addAll(cityMapper.selectChildrenCodesByCode(request.getCitycode()));
            
            // 使用自定义Mapper方法查询
            Page<StudentListData> result = baseMapper.selectStudentListWithDetails(
                    page, 
                    request.getTaskId(), 
                    request.getState(), 
                    request.getSchoolId(), 
                    request.getIsPic(), 
                    keyword,
                    codes
            );
            
            MyPage<StudentListData> myPage = MyPage.fromMybatisPlusPage(result);
            return Result.success(myPage);

        } catch (Exception e) {
            log.error("查询学生列表失败", e);
            return Result.error("查询失败");
        }
    }

    /**
     * 为抽测考试获取学生列表
     *
     * @param taskId 任务ID
     * @param citycode 城市码
     * @return 学生列表
     */
    public Result<MyPage<StudentListData>> getStudentListForCcExam(Integer taskId, String citycode) {
        try {
            // 验证任务是否存在
            Task task = taskMapper.selectById(taskId);
            if (task == null) {
                throw new BusinessException("任务不存在");
            }
            
            // 创建分页对象，使用默认的第1页和20条记录
            Page<StudentListData> page = new Page<>(1, 20);
            
            // 获取城市代码列表
            List<String> codes = new ArrayList<>();
            codes.add(citycode);
            codes.addAll(cityMapper.selectChildrenCodesByCode(citycode));
            
            // 使用自定义Mapper方法查询，状态为1（待考），照片为0（全部）
            Page<StudentListData> result = baseMapper.selectStudentListWithDetails(
                    page, 
                    taskId, 
                    1, // 状态：1待考
                    null, // 学校ID：不限
                    0, // 照片：0全部
                    null, // 关键字：无
                    codes
            );
            
            MyPage<StudentListData> myPage = MyPage.fromMybatisPlusPage(result);
            return Result.success(myPage);

        } catch (Exception e) {
            log.error("查询抽测考试学生列表失败", e);
            return Result.error("查询失败");
        }
    }

    /**
     * 清空考生
     *
     * @param taskId 任务ID
     * @return 清空结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> clearStudents(Integer taskId) {
        try {
            // 验证任务是否存在
            Task taskResult = taskMapper.selectById(taskId);
            if (taskResult == null) {
                return Result.error("任务不存在");
            }

            // 删除该任务下的所有学生
            LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Student::getTaskId, taskId);
            remove(wrapper);

            // 清空cc_school_student_count记录
            LambdaQueryWrapper<CcSchoolStudentCount> ccWrapper = new LambdaQueryWrapper<>();
            ccWrapper.eq(CcSchoolStudentCount::getTaskId, taskId);
            ccSchoolStudentCountMapper.delete(ccWrapper);

            return Result.success(null);

        } catch (Exception e) {
            log.error("清空考生失败", e);
            return Result.error("清空失败");
        }
    }

    /**
     * 学生锁定
     *
     * @param taskId 任务ID
     * @return 锁定结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> lockStudents(Integer taskId) {
        try {
            // 验证任务是否存在
            Task task = taskMapper.selectById(taskId);
            if (task == null) {
                return Result.error("任务不存在");
            }

            // 更新任务的学生锁定状态
            task.setStudentState(2);
            task.setSchoolState(1);
            taskMapper.updateById(task);

            ArrayList<CcSchoolStudentCount> ccs = new ArrayList<>();

            List<Student> students = baseMapper.selectList(Wrappers.lambdaQuery(Student.class).eq(Student::getTaskId, taskId));
            Map<Integer, Long> map = students.stream().collect(Collectors.groupingBy(Student::getSchoolId, Collectors.counting()));
            map.forEach((schoolId, count) -> {
                CcSchoolStudentCount ccSchoolStudentCount = new CcSchoolStudentCount()
                        .setTaskId(taskId)
                        .setSchoolId(schoolId)
                        .setCcCount(count.intValue())
                        .setIsDeleted(0)
                        .setCreatedTime(System.currentTimeMillis())
                        .setUpdatedTime(System.currentTimeMillis());

                ccs.add(ccSchoolStudentCount);
            });

            ccSchoolStudentCountMapper.insert(ccs);


            return Result.success(null);

        } catch (Exception e) {
            log.error("学生锁定失败", e);
            return Result.error("锁定失败");
        }
    }

    /**
     * 学生删除
     *
     * @param ids 学生ID列表
     * @return 删除结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> deleteStudents(List<Integer> ids) {
        try {
            if (ids == null || ids.isEmpty()) {
                return Result.error("学生ID不能为空");
            }

            boolean success = removeByIds(ids);

            if (success) {
                return Result.success(null);
            } else {
                return Result.error("删除失败");
            }

        } catch (Exception e) {
            log.error("删除学生失败", e);
            return Result.error("删除失败");
        }
    }

    /**
     * 学生修改
     *
     * @param citycode 城市码
     * @param request  修改请求
     * @return 修改结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateStudent(String citycode, StudentUpdateRequest request) {
        try {
            if (request.getId() == null) {
                return Result.error("学生ID不能为空");
            }

            Student student = getById(request.getId());
            if (student == null) {
                return Result.error("学生不存在");
            }

            // 更新字段
            if (StringUtils.hasText(request.getName())) {
                student.setName(request.getName());
            }
            if (request.getSex() != null) {
                student.setSex(request.getSex());
            }
            if (StringUtils.hasText(request.getStudentNo())) {
                student.setStudentNo(request.getStudentNo());
            }
            if (request.getGrade() != null) {
                student.setGrade(request.getGrade());
            }
            // 处理学校名
            if (StringUtils.hasText(request.getSchoolName())) {
                School school = findOrCreateSchool(request.getSchoolName(), citycode);
                student.setSchoolId(school.getId());
            }

//            // 处理考点名
//            if (StringUtils.hasText(request.getExamAddressName())) {
//                ExamAddress examAddress = findOrCreateExamAddress(request.getExamAddressName());
//                student.setExamAddressId(examAddress.getId());
//            }
//
//            // 处理考场名
//            if (StringUtils.hasText(request.getExamRoomName())) {
//                ExamRoom examRoom = findOrCreateExamRoom(request.getExamRoomName(), student.getExamAddressId());
//                student.setExamRoomId(examRoom.getId());
//            }

            boolean success = updateById(student);

            if (success) {
                return Result.success(null);
            } else {
                return Result.error("修改失败");
            }

        } catch (Exception e) {
            log.error("修改学生失败", e);
            return Result.error("修改失败");
        }
    }

    /**
     * 学生导入
     *
     * @param citycode 城市码
     * @param taskId   任务ID
     * @param file     导入文件
     * @return 导入结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> importStudents(String citycode, Integer taskId, MultipartFile file) {
        try {
            // 验证任务是否存在
            Task task = taskMapper.selectById(taskId);
            if (task == null) {
                throw new BusinessException("任务不存在");
            }

            // 获取城市代码列表
            List<String> codes = new ArrayList<>();
            codes.add(citycode);
            codes.addAll(cityMapper.selectChildrenCodesByCode(citycode));

            // 直接读取Excel数据流
            List<StudentImportDTO> dataList = new ArrayList<>();
            try (InputStream inputStream = file.getInputStream()) {
                EasyExcel.read(inputStream, StudentImportDTO.class, new StudentImportListener(dataList))
                        .sheet()
                        .doRead();
            }

            // 验证数据并转换为学生实体
            List<Student> students = new ArrayList<>();
            StringBuilder errorMsg = new StringBuilder();
            Map<String, Integer> studentNoMap = new HashMap<>(); // 用于检查重复学籍号

            // 收集所有需要的学校、考点、考场名称
            List<String> schoolNames = dataList.stream()
                    .map(StudentImportDTO::getSchoolName)
                    .distinct()
                    .filter(name -> name != null && !name.trim().isEmpty())
                    .collect(Collectors.toList());

            // 预先查询学校信息
            Map<String, School> schoolMap = new HashMap<>();
            if (!schoolNames.isEmpty()) {
                LambdaQueryWrapper<School> schoolQueryWrapper = new LambdaQueryWrapper<>();
                schoolQueryWrapper.in(School::getName, schoolNames);
                schoolQueryWrapper.in(School::getCitycode, codes);
                List<School> schools = schoolMapper.selectList(schoolQueryWrapper);
                schoolMap = schools.stream().collect(Collectors.toMap(School::getName, school -> school));
            }

            // 处理每行数据
            for (int i = 0; i < dataList.size(); i++) {
                StudentImportDTO dto = dataList.get(i);
                int rowNumber = i + 2; // Excel标题行+索引从0开始

                // 验证必填字段
                if (dto.getSchoolName() == null || dto.getSchoolName().trim().isEmpty()) {
                    errorMsg.append(String.format("第%d行：所在单位不能为空\n", rowNumber));
                    continue;
                }
                if (dto.getName() == null || dto.getName().trim().isEmpty()) {
                    errorMsg.append(String.format("第%d行：姓名不能为空\n", rowNumber));
                    continue;
                }
                if (dto.getStudentNo() == null || dto.getStudentNo().trim().isEmpty()) {
                    errorMsg.append(String.format("第%d行：学籍号不能为空\n", rowNumber));
                    continue;
                }
                if (dto.getGrade() == null || dto.getGrade().trim().isEmpty()) {
                    errorMsg.append(String.format("第%d行：年级不能为空\n", rowNumber));
                    continue;
                }

                // 验证学籍号长度
                if (dto.getStudentNo().length() != 19) {
                    errorMsg.append(String.format("第%d行：学籍号长度必须为19个字符\n", rowNumber));
                    continue;
                }

                // 检查学籍号重复（Excel内重复）
                if (studentNoMap.containsKey(dto.getStudentNo())) {
                    errorMsg.append(String.format("第%d行：学籍号%s在Excel中重复\n", rowNumber, dto.getStudentNo()));
                    continue;
                }
                studentNoMap.put(dto.getStudentNo(), rowNumber);

                // 创建学生实体
                Student student = new Student();
                student.setTaskId(taskId);
                student.setName(dto.getName().trim());
                student.setStudentNo(dto.getStudentNo().trim());
                student.setState(1);

                // 处理性别
                if ("男".equals(dto.getSex())) {
                    student.setSex(1);
                } else if ("女".equals(dto.getSex())) {
                    student.setSex(2);
                } else {
                    errorMsg.append(String.format("第%d行：性别只能为男或女\n", rowNumber));
                    continue;
                }

                // 处理年级
                NianjiEnum nianjiEnum = null;
            
                for (NianjiEnum item : NianjiEnum.values()) {
                    if (item.getDescription().equals(dto.getGrade().trim())) {
                        nianjiEnum = item;
                        break;
                    }
                }
                
                if (nianjiEnum == null) {
                    errorMsg.append(String.format("第%d行：年级格式不正确\n", rowNumber));
                    continue;
                }
                student.setGrade(nianjiEnum.getValue());

                // 处理学校
                School school = schoolMap.get(dto.getSchoolName().trim());
                if (school == null) {
                    errorMsg.append(String.format("第%d行：学校%s不存在\n", rowNumber, dto.getSchoolName().trim()));
                    continue;
                }
                student.setSchoolId(school.getId());

                students.add(student);
            }

            // 如果有错误信息，返回错误
            if (errorMsg.length() > 0) {
                return Result.error("数据验证失败：\n" + errorMsg.toString());
            }

            // 检查数据库中是否已存在学籍号
            if (!students.isEmpty()) {
                List<String> studentNos = students.stream()
                        .map(Student::getStudentNo)
                        .collect(Collectors.toList());
                
                LambdaQueryWrapper<Student> existQueryWrapper = new LambdaQueryWrapper<>();
                existQueryWrapper.in(Student::getStudentNo, studentNos);
                existQueryWrapper.eq(Student::getTaskId, taskId);
                existQueryWrapper.eq(Student::getIsDeleted, 0);
                List<Student> existingStudents = list(existQueryWrapper);
                
                if (!existingStudents.isEmpty()) {
                    StringBuilder existMsg = new StringBuilder("以下学籍号已存在：\n");
                    for (Student existingStudent : existingStudents) {
                        existMsg.append(existingStudent.getStudentNo()).append("\n");
                    }
                    return Result.error(existMsg.toString());
                }
            }

            // 批量插入学生数据
            if (!students.isEmpty()) {
                saveBatch(students, 100);
            }

            return Result.success(null);

        } catch (Exception e) {
            log.error("导入学生失败", e);
            return Result.error("导入失败：" + e.getMessage());
        }
    }

    /**
     * 导出学生导入模板
     *
     * @return 导出结果
     */
    public Result<String> exportStudentTemplate() {
        try {
            // 创建示例数据
            List<StudentImportDTO> dataList = new ArrayList<>();
            StudentImportDTO sample = new StudentImportDTO();
            sample.setSchoolName("abc");
            sample.setName("abc");
            sample.setSex("男");
            sample.setStudentNo("abc");
            sample.setGrade("一年级");
            dataList.add(sample);
            
            // 生成文件名和路径
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy_MM_dd_HH_mm_ss"));
            String fileName = "学生导入模板_" + timestamp + ".xlsx";
            String filePath = fileConfig.getExportDir() + "/" + fileName;
            
            // 创建目录
            Path path = Paths.get(filePath);
            Files.createDirectories(path.getParent());
            
            // 使用EasyExcel导出模板
            EasyExcel.write(filePath, StudentImportDTO.class)
                    .sheet("学生导入模板")
                    .doWrite(dataList);

            // 上传到MinIO
            File zipFile = new File(filePath);

            try (FileInputStream fis = new FileInputStream(zipFile)) {
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .bucket(minioConfig.getTemp())
                                .object(fileName)
                                .stream(fis, zipFile.length(), -1)
                                .contentType("application/zip")
                                .build()
                );
            }

            // 返回MinIO访问URL
            String fileUrl = "/files/" + minioConfig.getTemp() + "/" + fileName;

            // 删除本地临时文件
            Files.deleteIfExists(path);
            
            // 返回文件访问URL
            return Result.success(fileUrl);
            
        } catch (Exception e) {
            log.error("导出学生导入模板失败", e);
            return Result.error("导出失败：" + e.getMessage());
        }
    }

//    /**
//     * 学生人脸上传
//     *
//     * @param taskId    任务ID
//     * @param studentId 学生ID
//     * @param file      人脸图片文件
//     * @return 上传结果
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public Result<Void> uploadStudentFace(Integer taskId, Integer studentId, MultipartFile file) {
//        try {
//            // 验证任务是否存在
//            Result<Task> taskResult = taskService.getTaskInfo(taskId);
//            if (taskResult.getCode() != 200) {
//                return Result.error(taskResult.getMsg());
//            }
//
//            Task task = taskResult.getData();
//
//            // 验证任务状态
//            if (task.getStudentState() == 0) {
//                return Result.error("仅抽签后才可上传！");
//            }
//
//            long currentTime = System.currentTimeMillis() / 1000;
//            if (task.getState() != 0 && task.getStartAt() < currentTime) {
//                return Result.error("考试已经开始，不可操作！");
//            }
//
//            // 如果提供了学生ID，直接更新该学生
//            if (studentId != null && studentId > 0) {
//                Student student = getById(studentId);
//                if (student == null || !student.getTaskId().equals(taskId)) {
//                    return Result.error("学生不存在或不属于该任务");
//                }
//
//                String picUrl = minioUtil.saveUploadFile(file, minioConfig.getBucketStudentFace());
//                student.setPicUrl(picUrl);
//                updateById(student);
//
//            } else {
//                // 根据文件名匹配学生（文件名应该是学籍号）
//                String originalFilename = file.getOriginalFilename();
//                if (originalFilename == null) {
//                    return Result.error("文件名不能为空");
//                }
//
//                String studentNo = extractStudentNo(originalFilename);
//
//                LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
//                wrapper.eq(Student::getTaskId, taskId)
//                      .eq(Student::getStudentNo, studentNo);
//                Student student = getOne(wrapper);
//
//                if (student == null) {
//                    return Result.error("未找到学籍号为 " + studentNo + " 的学生");
//                }
//
//                String picUrl = minioUtil.saveUploadFile(file, minioConfig.getBucketStudentFace());
//                student.setPicUrl(picUrl);
//                updateById(student);
//            }
//
//            return Result.success(null);
//
//        } catch (Exception e) {
//            log.error("上传学生人脸失败", e);
//            return Result.error("上传失败：" + e.getMessage());
//        }
//    }
//
//    /**
//     * 批量上传学生人脸
//     *
//     * @param taskId 任务ID
//     * @param files  人脸图片文件列表
//     * @return 上传结果（包含失败信息）
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public Result<String> uploadStudentFaces(Integer taskId, List<MultipartFile> files) {
//        try {
//            // 验证任务是否存在
//            Result<Task> taskResult = taskService.getTaskInfo(taskId);
//            if (taskResult.getCode() != 200) {
//                return Result.error(taskResult.getMsg());
//            }
//
//            Task task = taskResult.getData();
//
//            // 验证任务状态
//            if (task.getStudentState() == 0) {
//                return Result.error("仅抽签后才可上传！");
//            }
//
//            long currentTime = System.currentTimeMillis() / 1000;
//            if (task.getState() != 0 && task.getStartAt() < currentTime) {
//                return Result.error("考试已经开始，不可操作！");
//            }
//
//            StringBuilder errorMsg = new StringBuilder();
//            int successCount = 0;
//
//            for (MultipartFile file : files) {
//                try {
//                    String originalFilename = file.getOriginalFilename();
//                    if (originalFilename == null) {
//                        errorMsg.append(file.getName()).append(": 文件名不能为空\n");
//                        continue;
//                    }
//
//                    String studentNo = extractStudentNo(originalFilename);
//
//                    LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
//                    wrapper.eq(Student::getTaskId, taskId)
//                          .eq(Student::getStudentNo, studentNo);
//                    Student student = getOne(wrapper);
//
//                    if (student == null) {
//                        errorMsg.append(originalFilename).append(": 未找到学籍号为 ").append(studentNo).append(" 的学生\n");
//                        continue;
//                    }
//
//                    String picUrl = minioUtil.saveUploadFile(file, minioConfig.getBucketStudentFace(), "student_faces");
//                    student.setPicUrl(picUrl);
//                    updateById(student);
//                    successCount++;
//
//                } catch (Exception e) {
//                    errorMsg.append(file.getOriginalFilename()).append(": ").append(e.getMessage()).append("\n");
//                }
//            }
//
//            if (errorMsg.length() > 0) {
//                return Result.error("部分文件上传失败（成功" + successCount + "个）：\n" + errorMsg.toString());
//            }
//
//            return Result.success(null);
//
//        } catch (Exception e) {
//            log.error("批量上传学生人脸失败", e);
//            return Result.error("上传失败：" + e.getMessage());
//        }
//    }

    // ========== 私有方法 ==========

    /**
     * 查找或创建学校
     */
    private School findOrCreateSchool(String schoolName, String citycode) {
        LambdaQueryWrapper<School> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(School::getName, schoolName)
              .eq(School::getCitycode, citycode);
        School school = schoolMapper.selectOne(wrapper);

        if (school == null) {
//            school = new School();
//            school.setName(schoolName);
//            school.setCitycode(citycode);
//            school.setIfEnable(0);
//            school.setAccountId(UserContext.getCurrentUserId());
//            schoolMapper.insert(school);
            throw new RuntimeException("未找到学校:" + schoolName);
        }

        return school;
    }

    /**
     * 从文件名中提取学籍号
     */
    private String extractStudentNo(String filename) {
        // 去掉扩展名
        int lastDot = filename.lastIndexOf(".");
        if (lastDot > 0) {
            return filename.substring(0, lastDot);
        }
        return filename;
    }

    /**
     * Excel读取监听器
     */
    private static class StudentImportListener implements ReadListener<StudentImportDTO> {
        private final List<StudentImportDTO> dataList;

        public StudentImportListener(List<StudentImportDTO> dataList) {
            this.dataList = dataList;
        }

        @Override
        public void invoke(StudentImportDTO data, AnalysisContext context) {
            dataList.add(data);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 读取完成后的操作
        }
    }
}
